public class KnightsOut {
	private int[] dRow = {1, 2, 2, 1, -1, -2, -2, -1, 0};
	private int[] dColumn = {2, 1, -1, -2, -2, -1, 1, 2, 0};

	public int count(int N, int M) {
		boolean[][] equation = new boolean[N * M][5 * M];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				for (int k = 0; k < 9; k++) {
					int newRow = i + dRow[k];
					int newColumn = j + dColumn[k];
					if (newRow >= 0 && newRow < N && newColumn >= 0 && newColumn < M) {
						equation[i * M + j][(newRow % 5) * M + newColumn] = true;
					}
				}
			}
		}
		int freedomDegrees = 0;
		for (int i = 0; i < N * M; i++) {
			int row = i / M;
			int variableIndex = (row % 5) * M + (i % M);
			int minIndex = Math.max(0, (row - 2) * M);
			int maxIndex = Math.min((row + 2) * M, N * M);
			int equationIndex = -1;
			for (int j = minIndex; j < maxIndex; j++) {
				if (equation[j][variableIndex]) {
					equationIndex = j;
					break;
				}
			}
			if (equationIndex == -1) {
				freedomDegrees++;
				continue;
			}
			for (int j = maxIndex - 1; j >= equationIndex; j--) {
				if (equation[j][variableIndex]) {
					int currentEquationRow = j / M;
					int minK = Math.max(0, Math.max(row, currentEquationRow) - 2);
					int maxK = Math.min(N - 1, Math.min(row, currentEquationRow) + 2);
					for (int k = minK; k <= maxK; k++) {
						int rowStart = (k % 5) * M;
						int rowFinish = rowStart + M;
						for (int l = rowStart; l < rowFinish; l++) {
							if (equation[equationIndex][l])
								equation[j][l] = !equation[j][l];
						}
					}
				}
			}
		}
		int res = 1;
		for (int i = 0; i < freedomDegrees; i++) {
			res *= 2;
			res %= 123456789;
		}
		return res;
	}


// BEGIN CUT HERE
	public static void main(String[] args) {
		if (args.length == 0) {
			KnightsOutHarness.run_test(-1);
		} else {
			for (int i=0; i<args.length; ++i)
				KnightsOutHarness.run_test(Integer.valueOf(args[i]));
		}
	}
// END CUT HERE
}

// BEGIN CUT HERE
class KnightsOutHarness {
	public static void run_test(int casenum) {
		if (casenum != -1) {
			if (runTestCase(casenum) == -1)
				System.err.println("Illegal input! Test case " + casenum + " does not exist.");
			return;
		}
		
		int correct = 0, total = 0;
		for (int i=0;; ++i) {
			int x = runTestCase(i);
			if (x == -1) {
				if (i >= 100) break;
				continue;
			}
			correct += x;
			++total;
		}
		
		if (total == 0) {
			System.err.println("No test cases run.");
		} else if (correct < total) {
			System.err.println("Some cases FAILED (passed " + correct + " of " + total + ").");
		} else {
			System.err.println("All " + total + " tests passed!");
		}
	}
	
	static boolean compareOutput(int expected, int result) { return expected == result; }
	static String formatResult(int res) {
		return String.format("%d", res);
	}
	
	static int verifyCase(int casenum, int expected, int received) { 
		System.err.print("Example " + casenum + "... ");
		if (compareOutput(expected, received)) {
			System.err.println("PASSED");
			return 1;
		} else {
			System.err.println("FAILED");
			System.err.println("    Expected: " + formatResult(expected)); 
			System.err.println("    Received: " + formatResult(received)); 
			return 0;
		}
	}

	static int runTestCase(int casenum) {
		switch(casenum) {
		case 0: {
			int N                     = 2;
			int M                     = 3;
			int expected__            = 4;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}
		case 1: {
			int N                     = 3;
			int M                     = 3;
			int expected__            = 1;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}
		case 2: {
			int N                     = 7;
			int M                     = 5;
			int expected__            = 16;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}
		case 3: {
			int N                     = 1;
			int M                     = 1;
			int expected__            = 1;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}
		case 4: {
			int N                     = 69;
			int M                     = 142;
			int expected__            = 77502052;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}

		// custom cases

/*      case 5: {
			int N                     = ;
			int M                     = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}*/
/*      case 6: {
			int N                     = ;
			int M                     = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}*/
/*      case 7: {
			int N                     = ;
			int M                     = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new KnightsOut().count(N, M));
		}*/
		default:
			return -1;
		}
	}
}

// END CUT HERE
